package main.java.DMDE.view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;

import com.jgoodies.forms.factories.CC;

import main.java.DMDE.controllers.IOperationController;
import main.java.DMDE.infrastructure.visual.OperationNode;
import main.java.DMDE.model.Attribute;
import main.java.DMDE.model.Method;
import main.java.DMDE.model.Modifier;
import main.java.DMDE.model.Parameter;
import main.java.DMDE.model.Type;
import main.java.DMDE.model.Visibility;

public class OperationView extends CommonView implements IOperationView {

    private IOperationController operatController;
    private JList<OperationNode> operatModelList;
    private DefaultListModel<OperationNode> operatModel;
    private Method operatSelected;
    private JLabel parameterName;
    private IParameterView parameterView;
    private JButton addParameter;
    private JButton editParameter;
    private JCheckBox absCheckBox;
    private List<Method> operations;

    public OperationView() {
	super();
	operations = new ArrayList<Method>();
    }

    @Override
    public JPanel getPanel() {
	return panel;
    }

    @Override
    public String getName() {
	return this.name.getText();
    }

    @Override
    public Type getReturnType() {
	return new Type(this.type.getText());
    }

    @Override
    public Visibility getVisibility() {
	if (btnPrivate.isSelected())
	    return Visibility.PRIVATE;
	else {
	    if (btnProtected.isSelected())
		return Visibility.PROTECTED;
	    else
		return Visibility.PUBLIC;
	}
    }

    @Override
    public List<Modifier> getModifiers() {
	List<Modifier> modifiers = new ArrayList<Modifier>();
	if (absCheckBox.isSelected())
	    modifiers.add(Modifier.ABSTRACT);
	if (finalCheckBox.isSelected())
	    modifiers.add(Modifier.FINAL);
	if (staticCheckBox.isSelected())
	    modifiers.add(Modifier.STATIC);
	return modifiers;
    }

    @Override
    public void setController(IOperationController operationController) {
	this.operatController = operationController;
    }

    @Override
    protected void create() {
	if (this.name.getText().equals("")) {
	    this.showNameError();
	} else {
	    Method operationCreated = operatController.addOperation();
	    if (operationCreated != null) {
		operatModel.addElement(new OperationNode(operationCreated));
		cleanView();
	    }
	}
    }

    @Override
    protected void edit() {
	if (operatSelected != null) {
	    if (this.operatController.editOperation(operatSelected)) {
		operatSelected = null;
		cleanView();
	    } else
		showNameError();
	}
    }

    private void showNameError() {
	JOptionPane.showMessageDialog(null, "Methods should have a name");
    }

    @Override
    protected void remove() {
	if (operatSelected != null) {
	    if (this.operatController.removeOperation(operatSelected)) {
		OperationNode node = operatModelList.getSelectedValue();
		operatModel.removeElement(node);
		operatSelected = null;
		cleanView();
	    }
	}
    }

    private void operationSelected(Method methodSelected) {
	if (methodSelected != null) {
	    this.operatSelected = methodSelected;
	    this.name.setText(operatSelected.getName());
	    this.type.setText(operatSelected.getReturnType().getName());
	    Visibility visibility = operatSelected.getVisibility();
	    if (visibility.equals(Visibility.PRIVATE))
		btnPrivate.doClick();
	    else {
		if (visibility.equals(Visibility.PROTECTED))
		    btnProtected.doClick();
		else
		    btnPublic.doClick();
	    }
	    List<Modifier> modifiers = operatSelected.getModifiers();
	    for (Modifier modif : modifiers) {
		if (modif.equals(Modifier.ABSTRACT))
		    absCheckBox.doClick();
		else {
		    if (modif.equals(Modifier.STATIC))
			staticCheckBox.doClick();
		    else
			finalCheckBox.doClick();
		}
	    }
	}

    }

    private void initParameter() {
	this.parameterName = new JLabel("Parameters: ");
	this.addParameter = new JButton();
	this.editParameter = new JButton();
	this.addParameter.setText("Add");
	this.editParameter.setText("Edit");
	panel.add(parameterName, CC.xy(4, 12));
	panel.add(addParameter, CC.xy(6, 12));
	panel.add(editParameter, CC.xy(8, 12));
	addParameter.addActionListener(new ActionListener() {
	    @Override
	    public void actionPerformed(ActionEvent actionEvent) {
		operatController.addParameter(operatSelected);
	    }
	});
	editParameter.addActionListener(new ActionListener() {
	    @Override
	    public void actionPerformed(ActionEvent actionEvent) {
		operatController.editParameter(operatSelected);
	    }
	});

    }

    @Override
    protected void initList() {

	initParameter();
	absCheckBox = new JCheckBox();
	absCheckBox.setText("Abstract");
	panel.add(absCheckBox, CC.xy(8, 6));
	this.operatModelList = new JList<OperationNode>();
	scrollPane.setViewportView(operatModelList);
	operatModel = new DefaultListModel<OperationNode>();
	operatModelList.setModel(operatModel);
	this.operatSelected = null;
	operatModelList.addListSelectionListener(new ListSelectionListener() {

	    @Override
	    public void valueChanged(ListSelectionEvent e) {
		if (!e.getValueIsAdjusting()) {
		    if (operatModelList.getSelectedValue() instanceof OperationNode) {
			Method methodSelected = ((OperationNode) operatModelList
				.getSelectedValue()).getMethod();
			operationSelected(methodSelected);
		    } else {
			operatSelected = null;
		    }
		}
	    }
	});

	operatModelList.addKeyListener(new KeyListener() {

	    @Override
	    public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_DELETE) {
		    if (operatModelList.getSelectedValue() instanceof OperationNode) {
			// OperationNode operatNode =
			// (OperationNode)operatModelList.getSelectedValue();
			// TODO:terminar
			// operatModel.removeNode((OperationNode)operatModelList.getSelectedValue());
			cleanView();
		    }
		}

	    }

	    @Override
	    public void keyReleased(KeyEvent arg0) {

	    }

	    @Override
	    public void keyTyped(KeyEvent arg0) {

	    }
	});

    }

    @Override
    protected void cleanTree() {
	if (absCheckBox.isSelected())
	    absCheckBox.doClick();
	operatModelList.revalidate();
	operatModelList.repaint();
	operatModelList.updateUI();
	operatModelList.clearSelection();
    }

    @Override
    public void addParameterView(IParameterView parameterView) {
	this.parameterView = parameterView;
	this.parameterView.getFrame().setVisible(true);
    }

    @Override
    public List<Method> getOperations() {
	loadOperations();
	return operations;
    }

    @Override
    public void loadOperations() {
	for (int i = 0; i < operatModel.getSize(); i++) {
	    operations.add(operatModel.getElementAt(i).getMethod());
	}
    }
    
    @Override
    public void setOperations(List<Method> operations) {
	this.operations = operations;
	for(Method operat : operations){
	    operatModel.addElement(new OperationNode(operat));
	}
    }

    @Override
    public void disableInterfaceVisibility() {
	this.btnPrivate.setEnabled(false);
	this.btnProtected.setEnabled(false);
    }

    @Override
    public void disableInterfaceModifier() {
	this.staticCheckBox.setEnabled(false);
	this.finalCheckBox.setEnabled(false);
    }

    @Override
    public void setParameters(IParameterView parameterView,List<Parameter> parameters){
	parameterView.setParameters(parameters);	
    }

    @Override
    public List<Parameter> getParameters() {
	return parameterView.getParameters();
    }
}
